package com.qianda.qdminiapp.service.pay;

import com.qianda.qdminiapp.common.exception.ExceptionCode;
import com.qianda.qdminiapp.common.exception.PayServiceException;
import com.qianda.qdminiapp.common.exception.SimpleException;
import com.qianda.qdminiapp.common.util.PayUtil;
import com.qianda.qdminiapp.common.util.RandomUtil;
import com.qianda.qdminiapp.common.util.StringUtils;
import com.qianda.qdminiapp.config.WxpayProperties;
import com.qianda.qdminiapp.domain.data.WithdrawHandlerData;
import com.qianda.qdminiapp.domain.model.activity.QqdRedpacketAmtDetail;
import com.qianda.qdminiapp.domain.model.activity.QqdRedpacketDrawLog;
import com.qianda.qdminiapp.domain.model.order.Order;
import com.qianda.qdminiapp.domain.model.order.QqdOrderInfo;
import com.qianda.qdminiapp.domain.model.order.QqdOrderTowel;
import com.qianda.qdminiapp.domain.model.user.QqdUser;
import com.qianda.qdminiapp.service.client.ServiceException;
import com.qianda.qdminiapp.service.protocols.DeviceProtocolsV1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName WxPayment
 * @Author cw
 * @Date 2019/8/7 13:46
 * @Version 1.0
 */
public class WxPayment {

    private static Logger LOGGER = LoggerFactory.getLogger(WxPayment.class);

    /**
     * @Description: 发起微信支付
     */
    public  Map<String, Object> wxPay(String openid, QqdOrderInfo qqdOrderInfo, WxpayProperties wxPayConfig) {
        try {
            // 生成的随机字符串
            String nonce_str = StringUtils.getRandomStringByLength(32);
            // 商品名称
            //String body = requestPd.getString("orderBody");
            String body = "毛巾";
            // 获取客户端的ip地址
         //   String spbill_create_ip = request.getRemoteAddr();

            // 组装参数，用户生成统一下单接口的签名
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", wxPayConfig.getAppid());
            packageParams.put("mch_id",wxPayConfig.getMch_id());
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", qqdOrderInfo.getOrderNo());// 商户订单号
            String money  = qqdOrderInfo.getOrderAmt().multiply(new BigDecimal("100")).intValue()+"";

                    LOGGER.info("WxPay支付订单money：" + money);
            packageParams.put("total_fee", money);// 支付金额，这边需要转成字符串类型，否则后面的签名会失败
          //  packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", wxPayConfig.getNotify_url());// 支付成功后的回调地址
            packageParams.put("trade_type", "JSAPI");// 支付方式
            packageParams.put("openid", openid);

            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

            // MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, wxPayConfig.getKey(), "utf-8").toUpperCase();

            // 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + wxPayConfig.getAppid() + "</appid>" + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + wxPayConfig.getMch_id() + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + wxPayConfig.getNotify_url() + "</notify_url>" + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + qqdOrderInfo.getOrderNo() + "</out_trade_no>"
                   // + "<spbill_create_ip>"
                  //  + spbill_create_ip
                   // + "</spbill_create_ip>"
                    + "<total_fee>" + money
                    + "</total_fee>" + "<trade_type>" + "JSAPI" + "</trade_type>" + "<sign>" + mysign
                    + "</sign>" + "</xml>";

            // System.out.println("调试模式_统一下单接口 请求XML数据：" + xml);
            LOGGER.info("--------返回的xml-------:" + xml);
            // 调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(wxPayConfig.getPay_url(), "POST", xml);

            LOGGER.info("调试模式_统一下单接口 返回XML数据：" + result);

            // 将解析结果存储在HashMap中
            Map map = PayUtil.doXMLParse(result);

            String return_code = (String) map.get("return_code");// 返回状态码

            Map<String, Object> response = new HashMap<String, Object>();// 返回给小程序端需要的参数
            if ( "SUCCESS".equals(return_code)) {
                String prepay_id = (String) map.get("prepay_id");// 返回的预付单信息
                response.put("nonceStr", nonce_str);
                response.put("package", "prepay_id=" + prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                response.put("timeStamp", timeStamp + "");// 这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                // 拼接签名需要的参数
                String stringSignTemp = "appId=" + wxPayConfig.getAppid() + "&nonceStr=" + nonce_str + "&package=prepay_id="
                        + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
                // 再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, wxPayConfig.getKey(), "utf-8").toUpperCase();
                response.put("paySign", paySign);
            }else{
                throw new SimpleException(ExceptionCode.EX_PAY_WAY_ERR);
            }
            response.put("orderNo", qqdOrderInfo.getOrderNo());
            response.put("appid",wxPayConfig.getAppid());

            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public  Map<?,?>  WxRefund(QqdOrderTowel order, QqdOrderInfo qqdOrderInfo, WxpayProperties wxPayConfig) {

        LOGGER.info("进入退款信息");
        try {
            // 生成的随机字符串
            String nonce_str = StringUtils.getRandomStringByLength(32);
            // 商品名称
            String body = "退款";
            // 获取客户端的ip地址
            //String spbill_create_ip = request.getRemoteAddr();
            // 退款单号
            String out_refund_no = RandomUtil.getId();

            // 组装参数，用户生成统一下单接口的签名
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", wxPayConfig.getAppid());
            packageParams.put("mch_id", wxPayConfig.getMch_id());
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("out_refund_no", out_refund_no);//退款单号
            packageParams.put("out_trade_no", qqdOrderInfo.getOrderNo());// 商户订单号
           // packageParams.put("notify_url", wxPayConfig.getRefundNotifyUrl());// 退款成功通知

            String money  = order.getOrderAmt().multiply(new BigDecimal("100")).intValue()+"";


            packageParams.put("total_fee",money);// 支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("refund_fee", money);// 退款金额


            // packageParams.put("openid", openid);
            // packageParams.put("body", body);
            // packageParams.put("spbill_create_ip", spbill_create_ip);
            // packageParams.put("notify_url", WxPayConfig.notify_url);// 支付成功后的回调地址
            // packageParams.put("trade_type", WxPayConfig.TRADETYPE);// 支付方式

            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            LOGGER.info("退款连接值:"+prestr);
            // MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, wxPayConfig.getKey(), "utf-8").toUpperCase();

            // 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>"
                    + "<appid>" + wxPayConfig.getAppid() + "</appid>"
                    + "<mch_id>" + wxPayConfig.getMch_id() + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<out_refund_no>" + out_refund_no + "</out_refund_no>"
                    + "<out_trade_no>" + order.getOrderNo() + "</out_trade_no>"
                 //   + "<notify_url>" +  wxPayConfig.getRefundNotifyUrl() + "</notify_url>"
                    + "<total_fee>" + money + "</total_fee>"
                    + "<refund_fee>" + money + "</refund_fee>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";

          LOGGER.info("调试模式_统一下单接口 请求XML数据："+xml);
            // 调用统一退款接口，并接受返回的结果
            String result = ClientCustomSSL.doRefund(wxPayConfig.getRefund_url(), xml,wxPayConfig);
            LOGGER.info("退款接口返回值："+result);

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;

    }

    public WithdrawHandlerData companyPay(QqdUser user, QqdRedpacketDrawLog qqdRedpacketDrawLog, WxpayProperties wxPayConfig) {
        Map<String, Object> response = new HashMap<String, Object>();// 返回给小程序端需要的参数
        WithdrawHandlerData resultData = new WithdrawHandlerData();
        // try {
        // 生成的随机字符串
        String nonce_str = StringUtils.getRandomStringByLength(32);
        // 商品名称
        //String body = requestPd.getString("orderBody");
        String desc = "红包";
        // 获取客户端的ip地址
       // String spbill_create_ip = request.getRemoteAddr();
        String checkName = "NO_CHECK";
        // 组装参数，用户生成统一下单接口的签名
        Map<String, String> packageParams = new HashMap<String, String>();
        packageParams.put("mch_appid", wxPayConfig.getAppid());
        packageParams.put("mchid",wxPayConfig.getMch_id().trim());
        packageParams.put("nonce_str", nonce_str);
        //   packageParams.put("body", body);
        packageParams.put("partner_trade_no", qqdRedpacketDrawLog.getDrawNo());// 商户订单号
        packageParams.put("openid", user.getUserOpenId());
        packageParams.put("check_name", checkName);//强校验真实姓名    NO_CHECK：不校验真实姓名
      //  packageParams.put("re_user_name", qqdWithdrawApplication.getRealName());

        BigDecimal amount = qqdRedpacketDrawLog.getDrawAmt().multiply(new BigDecimal("100"));
        String amt =  amount.intValue()+"";
        packageParams.put("amount", amt);
        packageParams.put("desc", desc);
        packageParams.put("spbill_create_ip", "39.105.3.48");

        String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

        // MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
        String mysign = PayUtil.sign(prestr, wxPayConfig.getKey(), "utf-8").toUpperCase();

        // 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
        String xml = "<xml>" + "<mch_appid>" + wxPayConfig.getAppid() + "</mch_appid>"
                + "<mchid>" + wxPayConfig.getMch_id().trim() + "</mchid>" + "<nonce_str>" + nonce_str + "</nonce_str>"
                + "<partner_trade_no>" +   qqdRedpacketDrawLog.getDrawNo() + "</partner_trade_no>" + "<openid>" + user.getUserOpenId() + "</openid>"
                + "<check_name>" + checkName + "</check_name>"
             //   + "<re_user_name>" + qqdWithdrawApplication.getRealName() + "</re_user_name>"
                + "<amount>" + amt + "</amount>"
                + "<desc>" + desc + "</desc>"
                + "<spbill_create_ip>" + "39.105.3.48" + "</spbill_create_ip>"
                + "<sign>" + mysign + "</sign>" + "</xml>";

        // System.out.println("调试模式_统一下单接口 请求XML数据：" + xml);
        LOGGER.info("--------返回的xml-------:" + xml);

        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
        // 调用统一下单接口，并接受返回的结果
        //   String result = PayUtil.httpRequest(url, "POST", xml);

        String result = null;
        try {
            result = ClientCustomSSL.doWithdraw(url, xml,wxPayConfig);
        } catch (Exception e) {
            e.printStackTrace();
        }


        LOGGER.info("调试模式_统一下单接口 返回XML数据：" + result);

        // 将解析结果存储在HashMap中
        Map map = null;
        try {
            map = PayUtil.doXMLParse(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String return_code = (String) map.get("return_code");// 返回状态码
        if("SUCCESS".equals(return_code)){
            String result_code = (String) map.get("result_code");// 返回状态码
            if ( "SUCCESS".equals(result_code)) {
                //response.put("returnCode","SUCCESS");
                String paymentNo = (String) map.get("payment_no");// 返回状态码
                resultData.setReturnNo(paymentNo);
                resultData.setResultCode("SUCCESS");
                return resultData;
            }else if("FAIL".equals(result_code)){
                resultData.setResultCode("FAIL");
                String err_code = (String) map.get("err_code");// 错误码
                Integer failHandlerCode = 0;
                resultData.setFailHandlerCode(failHandlerCode);

                if("NO_AUTH".equals(err_code)){
                    LOGGER.error("没有该接口权限" );
                    resultData.setReturnFailReason("没有该接口权限");
                    throw new SimpleException(ExceptionCode.EX_SYS_ORGIN_ERROR);


                }else if("AMOUNT_LIMIT".equals(err_code)){
                    LOGGER.error("付款金额超出限制。低于最小金额1.00元或累计超过5000.00元。" );
                    resultData.setReturnFailReason("付款金额超出限制。低于最小金额1.00元或累计超过5000.00元。");
                    resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_WITHDRAW_AMT_ERROR);

                }else if("PARAM_ERROR".equals(err_code)){
                    LOGGER.error("参数错误" );
                    resultData.setReturnFailReason("参数错误");
                    throw new SimpleException(ExceptionCode.EX_HTTP_INPUT_NOT_VALID);


                }else if("OPENID_ERROR".equals(err_code)){
                    LOGGER.error("Openid错误" );
                    resultData.setReturnFailReason("Openid错误");
                    throw new SimpleException(ExceptionCode.EX_WITHDRAW_OPEN_ID_ERROR);


                }else if("SEND_FAILED".equals(err_code)){
                    LOGGER.error("付款错误" );
                    resultData.setReturnFailReason("付款错误");
                    throw new SimpleException(ExceptionCode.EX_WITHDRAW_PAY_ERROR);


                }else if("NOTENOUGH".equals(err_code)){
                    LOGGER.error("余额不足" );
                    resultData.setReturnFailReason("余额不足");
                    throw new SimpleException(ExceptionCode.EX_BALLANCE_NOT_ENOUGH);

                }else if("SYSTEMERROR".equals(err_code)){
                    LOGGER.error("系统繁忙，请稍后再试。" );
                    resultData.setReturnFailReason("系统繁忙，请稍后再试。");
                    throw new SimpleException(ExceptionCode.EX_SYSTEM);

                }else if("NAME_MISMATCH".equals(err_code)){
                    LOGGER.error("姓名校验出错" );
                    resultData.setReturnFailReason("姓名校验出错");
                    resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_WITHDRAW_ACCOUNT_REALNAME_ERROR);


                }else if("SIGN_ERROR".equals(err_code)){
                    LOGGER.error("签名错误" );
                    resultData.setReturnFailReason("签名错误");
                    throw new SimpleException(ExceptionCode.EX_SIGN_ERROR);


                }else if("FREQ_LIMIT".equals(err_code)){
                    LOGGER.error("超过频率限制，请稍后再试。" );
                    resultData.setReturnFailReason("超过频率限制，请稍后再试。");
                    throw new SimpleException(ExceptionCode.EX_FREQUENT_ERROR);


                }else if("MONEY_LIMIT".equals(err_code)){
                    LOGGER.error("已经达到今日付款总额上限/已达到付款给此用户额度上限" );
                    resultData.setReturnFailReason("已经达到今日付款总额上限/已达到付款给此用户额度上限");
                    //     resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_PAY_ENOUGH_ERROR);


                }else if("CA_ERROR".equals(err_code)){
                    LOGGER.error("商户API证书校验出错。" );
                    resultData.setReturnFailReason("商户API证书校验出错。");
                    //resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_SYSTEM);

                }else if("V2_ACCOUNT_SIMPLE_BAN".equals(err_code)){
                    LOGGER.error("无法给未实名用户付款。" );
                    resultData.setReturnFailReason("无法给未实名用户付款。");
                    resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_USER_ID_ERROR);

                }else if("SENDNUM_LIMIT".equals(err_code)){
                    LOGGER.error("该用户今日付款次数超过限制。" );
                    resultData.setReturnFailReason("该用户今日付款次数超过限制。");
                    //   resultData.setFailHandlerCode(1);
                    throw new SimpleException(ExceptionCode.EX_TODAY_PAY_ERROR);

                }
            }
        }else{
            String return_msg = (String) map.get("return_msg");// 返回状态码

            throw new PayServiceException(100012,return_msg);
        }

        // } catch (Exception e) {
        //    e.printStackTrace();
        //  }
        // response.put("returnCode","FAIL");

        return resultData;
    }

}
